Ruby on Rails Cheat Sheet


rails 데이터 타입

:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean

Rails Mimetype   

"./."                      => :all
"text/plain"               => :text
"text/html"                => :html
"application/xhtml+xml"    => :html
"text/javascript"          => :js
"application/javascript"   => :js
"application/x-javascript" => :js
"text/calendar"            => :ics  
"text/csv"                 => :csv  
"application/xml"          => :xml
"text/xml"                 => :xml
"application/x-xml"        => :xml
"text/yaml"                => :yaml
"application/x-yaml"       => :yaml
"application/rss+xml"      => :rss  
"application/atom+xml"     => :atom 
"application/json"         => :json
"text/x-json"              => :json

bundle asset precompile

bundle exec rake assets:precompile RAILS_ENV="production"
rake assets:clean< add below code if you want development environment with out precompile config.serve.static.assets = false application.rb use Bundler.require(:default, :assets, Rails.env) instead of Bundler.require(*Rails.groups(:assets => %w(development test)))

compile assets locally

Put below into development.rb
config.assets.prefix = "/temp-assets"
Also put below into application.rb
config.assets.initialize.on.precompile = false

rails logger

Rails.logger.info "My info message"
Rails.logger.debug "My debugging message"
Rails.logger.warn "My warning message"

Environment Log level

config.log_level = :debug, :info, :warn, :error, and :fatal

Validation text length CR filter

before.validation :replace.cr
  protected
  def replace.cr
    if self.description.changed?
      self.description.gsub!(/\r\n?/, "\n")
    end
  end

validation locale


// config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"
If you are using mongoid, replace activerecord: with mongoid:

Validate associated

The answer to this turned out to be rather simple. On the parent model, you simply explicitly declare that you want the associated children validated.
parent.rb
validates_associated :children

Validate if persisted? or new_record?

validates.uniqueness.of :nickname, :message => I18n.t("user.already.taken"), :if => :new.record?
validates.uniqueness.of :nickname, :message => I18n.t("user.already_taken"), :unless => :persisted?

Session Store in rails 3

Use the database for sessions instead of the cookie-based default, which shouldn't be used to store highly confidential information
Create the session table with
rake db:sessions:create
Run the migration
rake db:migrate
Make sure you also tell rails to use ActiveRecord to manage your sessions too.
Rails 3
config/initializers/session.store.rb:
Rails.application.config.session.store :active.record.store

DB Migrate Production

rake db:migrate RAILS_ENV="production"

get rails environment

Rails.env
env["SERVER_NAME"]

rails template

rake print --silent RECIPES=jquery,haml,rspec,cucumber,guard,mongoid,action.mailer,devise,add.user,home.page,home.page.users,seed.database,users.page,css.setup,application.layout,html5,navigation,cleanup,ban.spiders,extras,git,compass,omniauth,omniauth.email,backbone > ~/Desktop/backbone.template.txt
Could you please run it again using the "-T -O -J" flags? As in
rails new template_test -m https://github.com/fortuity/rails3-application-templates/raw/master/rails3-mongoid-devise-template.rb -T -O -J
http://blog.dominicsayers.com/2011/08/16/howto-use-a-rails-template-from-github-on-windows/

thin start

D:\dev\ruby192\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) D:/dev/workspace/baksisi/script/rails server thin -b 127.0.0.1 -p 3002 -e development
ruby ./script/rails server thin -b smoke-free-online.de -p 3000 -e development -d
thin start

Middle Man

"server" was called incorrectly. Call as "middleman server [-p 4567] [-e development]".
"middleman server [-p 4567] [-e development]" instead of "middleman server -p 4567 -e development

DB migration

Rails g migration change.data.type.for.table_column

I18n

locale join

config/application.rb
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '.*', '..{rb,yml}')]

locale path

routes.rb
  match '/:locale' => "home#index"
  root :to => "home#index"
  scope "/:locale" do   
    controller :models do
      something
    end
    resources :models, :only => :show
ApplicationController
  def default.url.options(options = {})
    options.merge!({:locale => I18n.locale})
  end   

Localize

I18n.l Time.now, :format => :short,  :locale => :"ko"

Pluralization

ko:
  pears:
    zero: ko.zero
    one: ko.one
    few: ko.few
    other: ko.other

generate rake tasks

rails g task namespace task1 task2
rake -T | grep namespace

세션 저장

config.session.store :cookie.store, :key => '.baksisi.session', :domain => :all
environment.rb 메일러에 레이아웃을 지정하고 싶다면.
DeviseMailer.layout "OMG"

show routes

rake routes

SASS

config/application.rb:
config.generators.stylesheet_engine = :sass
sass-convert style.sass style.scss

Trouble Shootings

uninitialized constant

file name confirm (if file name capital, it can be occurred.)

guard-livereload error

gem install eventmachine --pre 

open-uri.rb file in C:/Ruby1.9.2/lib/ruby/1.9.1/ (of course your path might be different).

http.verify.mode = options[:ssl.verify.mode] || OpenSSL::SSL::VERIFY.NONE

[ERROR] V8 is no longer usable

ulimit -v unlimited  

CSV Data Handling

http://www.ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html

get action information at view

    params[:action]

HAML

rails helper using haml
 
def section(name)
haml.tag(:div, :class => 'section') do
  haml.tag(:h2, name)
  haml.tag(:p, :class => 'section.content') do
    yield
  end
end
end
      
def content.box
  haml.tag :div, :class => "holder" do
    haml.tag :div, :class => "top"
    haml.tag :div, :class => "content" do
      yield
    haml.tag :div, :class => "bottom"
  end
end
and in haml
%html
  %head
  %body
    Maybee some content here.
    - content.box do
      Content that goes in the content_box like news or stuff      
     
fields_for with index
<% @questions.each.with.index do |question,index| %>
    <% f.fields.for :questions, question do |fq| %> 
        # here you have both the 'question' object and the current 'index'
    <% end %>
<% end %>
It’s also possible to specify the instance to be used:
<%= form.for @person do |person.form| %>
...
<% @person.projects.each do |project| %>
  <% if project.active? %>
    <%= person.form.fields.for :projects, project do |project.fields| %>
      Name: <%= project.fields.text_field :name %>
    <% end %>
  <% end %>
<% end %>
<% end %>     

Rails Response

namespace "api" do
  resources :regions, :defaults => { :format => 'xml' }
end
Then you should be able to have the following work for your controller methods:
class Api::RegionsController < ApplicationController
  respond.to :xml, :json
  def index
    respond.with(@regions = Region.all)
  end
end
rescue.from  ActionController::MissingFile do |e|
  # User's browser probably wont display this
  # Content-Type is application/x-shockwave-flash
  render :file => File.join(Rails.public.path, '404.html'), :status => 404
end

show details or stream video

def show
  @media = Media.find params[:id]
  respond.to do |format|
    format.html
    format.flv { send.file @media.path, :disposition => 'inline' }
  end
end
render :file => File.join(Rails.public.path, '404.html'), :status => 404, :content.type => 'text/html'

render with variable

render :partial => "my/conejo", :locals => {:my.val => something}
render "my/liebre", :my.val => something

scope

default_scope order('id DESC')
Model.reorder('')
Model.unscoped

render an other action in the controller, in js.

  render 'result', :id => @item.id, :format => :js
 

layout xhr? 

  class ApplicationController < ActionController::Base
  layout proc{|c| c.request.xhr? ? false : "application" }
  end
  layout :layout.xhr?
  def layout.xhr?
    request.xhr? ? false : 'application'
  end
 

AJAX Performance stale? and touch


 def show
    @list_item = @list.list_items.find( params[ :id ] )
    if stale?( :etag => @list_item, :last_modified => @list_item.updated_at.utc, :public => true )
      respond_with( @list_item )
    end
  end
  Also instead of the update_list method being called from after_save/destroy you can pass :touch => true to the belongs_to association which will do the same

AJAX Handler - ?xhr

respond_with( @something, :layout => !request.xhr? )
or
respond_to do |wants|
  wants.html do
    if request.xhr?
      render :partial => "items"
    else
      render
    end
  end
end

Asset

exist

YourApp::Application.assets.find_asset("#{asset}.file").nil?

### pathname

<YourAppName>::Application.assets.find_asset('Rails.png').pathname

absolute asset_path in view using helper

"#{request.protocol}#{request.host.with.port}#{asset.path('person/gravatar.default.png')}"
"#{request.scheme}://#{request.host.with.port}#{request.script_name}"

Mailer

config

environment/production.rb
  config.action.mailer.default.url.options = {:host => 'localhost:3000',:locale =>I18n.locale}
  config.action.mailer.smtp.settings = {
    :address              => "server.addr",
    :port                 => 587,
    :domain               => "sever.domain",
    :user.name            => "user.name",
    :password             => "user.password",
    :authentication       => "plain",
    :enable.starttls.auto => true
  } 
  config.action.mailer.delivery.method = :smtp
  config.action.mailer.perform.deliveries = true
  config.action.mailer.raise.delivery.errors = false
  config.action.mailer.default :charset => "utf-8"

inline attachement

in mailer

attachments.inline['blank'] = {
    :data => File.read("#{Rails.root.to.s + '/app/assets/images/blank.png'}"),
    :mime.type => "image/png",
    :encoding => "base64"
}

in view

if @offer.image.nil?
  = image.tag( attachments['blank'].url, :id => 'attachement.image', :width => "400", :height => "400")
 

validates in I18n

%{attribute} - field name
%{model} - model name 
%{count} - count


rescue log

begin
  ...some code...
rescue Exception => e
  logger.error e.message
 

Ruby

Iterate

a.each.with.index do |item, index|
  puts item, b[index]
end
array.each.slice(3) do |elements|
  fire.the_event
end

Timezone

in client (js):
function set.time.zone.offset() {
    var current.time = new Date();
    $.cookie('time.zone', current.time.getTimezoneOffset());
}
in Application Controller:
before.filter :set.timezone
def set.timezone 
 min = request.cookies["time.zone"].to_i
 Time.zone = ActiveSupport::TimeZone[-min.minutes]
end

DateTime format

  %a - The abbreviated weekday name (Sun)
&nbsp; %A - The&nbsp; full&nbsp; weekday&nbsp; name (Sunday)
  %b - The abbreviated month name (Jan)
&nbsp; %B - The&nbsp; full&nbsp; month&nbsp; name (January)
  %c - The preferred local date and time representation
  %d - Day of the month (01..31)
  %H - Hour of the day, 24-hour clock (00..23)
  %I - Hour of the day, 12-hour clock (01..12)
  %j - Day of the year (001..366)
  %m - Month of the year (01..12)
  %M - Minute of the hour (00..59)
  %p - Meridian indicator (AM&nbsp; or&nbsp;PM)
  %S - Second of the minute (00..60)
  %U - Week  number  of the current year,
          starting with the first Sunday as the first
          day of the first week (00..53)
  %W - Week  number  of the current year,
          starting with the first Monday as the first
          day of the first week (00..53)
  %w - Day of the week (Sunday is 0, 0..6)
  %x - Preferred representation for the date alone, no time
  %X - Preferred representation for the time alone, no date
  %y - Year without a century (00..99)
  %Y - Year with century
  %Z - Time zone name
  %% - Literal ``%'' character
   t = Time.now
   t.strftime("Printed on %m/%d/%Y")   #=> "Printed on 04/09/2003"
   t.strftime("at %I:%M%p")            #=> "at 08:56AM"
  
   datetime seconds, hours, days, weeks, months, and years
  
    Add below lines to one of your initializer files, e.g., config/environment.rb:
    DateTime::DATE.FORMATS[:short]="short %Y-%m-%d %H:%M:%S"
    Time::DATE.FORMATS[:short] = "short %Y-%m-%d %H:%M:%S"
    Date::DATE.FORMATS[:short] = "short %Y-%m-%d"
    modify view:
    <%= item.create_date.to_s(:short) %>
distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
today = DateTime.now
=> #<DateTime: 441799066630193/180000000,-301/1440,2299161>
birthday = Date.new(2008, 4, 10)
=> #<Date: 4909133/2,0,2299161>
days_to_go = birthday - today
time_until = birthday - today
=> Rational(22903369807, 180000000)
time_until.to_i             # get the number of days until my birthday
=> 127
hours,minutes,seconds,frac = Date.day_fraction.to_time(time_until)
[3053, 46, 57, Rational(1057, 180000000)]
- mm  = (now-la    st_cigarette).divmod(Rational(1, 1440))[0]
- past.days = mm / 1440
- past.hours = (mm % 1440) / 60
- past_minutes = mm % 60

timezone

def set_api_time_zone
  utc_offset = current.user.session && current.user.session.user ? current.user.session.user.time.zone.offset.to.i.minutes : 0
  user.timezone = ActiveSupport::TimeZone[utc.offset]
  Time.zone = user.timezone if user.timezone
  Time.zone.today
  Time.now.to.date
    # => Thu, 19 May 2011
  Time.now.in.time.zone('Melbourne').to_date
    # => Fri, 20 May 2011
end

Range step

range.step(2) {|x| puts x}


benchmark

require 'benchmark'
n = 1000000
def answer1 current.subdomain
  case current.subdomain
  when 'www', 'blog', 'foo', 'bar'
  else nil
  end
end
def answer2 current.subdomain
  nil unless  ["www", "blog", "foo", "bar"].include?(current.subdomain)
end
Benchmark.bmbm do |b|
  b.report('answer1'){n.times{answer1('bar')}}
  b.report('answer2'){n.times{answer2('bar')}}
end
Rehearsal -------------------------------------------
answer1   0.290000   0.000000   0.290000 (  0.286367)
answer2   1.170000   0.000000   1.170000 (  1.175492)
---------------------------------- total: 1.460000sec
              user     system      total        real
answer1   0.290000   0.000000   0.290000 (  0.282610)
answer2   1.180000   0.000000   1.180000 (  1.186130)
Benchmark.bmbm do |b|
  b.report('answer1'){n.times{answer1('hello')}}
  b.report('answer2'){n.times{answer2('hello')}}
end
Rehearsal -------------------------------------------
answer1   0.250000   0.000000   0.250000 (  0.252618)
answer2   1.100000   0.000000   1.100000 (  1.091571)
---------------------------------- total: 1.350000sec
              user     system      total        real
answer1   0.250000   0.000000   0.250000 (  0.251833)
answer2   1.090000   0.000000   1.090000 (  1.090418)


출처